1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.util.concurrent;
18
19 import com.google.common.base.Preconditions;
20
21 import junit.framework.TestCase;
22
23 import org.mockito.Mockito;
24
25 import java.util.concurrent.CancellationException;
26 import java.util.concurrent.Executor;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.TimeUnit;
29
30 import javax.annotation.Nullable;
31
32
33
34
35
36
37 public class FutureCallbackTest extends TestCase {
38 public void testSameThreadSuccess() {
39 SettableFuture<String> f = SettableFuture.create();
40 MockCallback callback = new MockCallback("foo");
41 Futures.addCallback(f, callback);
42 f.set("foo");
43 }
44
45 public void testExecutorSuccess() {
46 CountingSameThreadExecutor ex = new CountingSameThreadExecutor();
47 SettableFuture<String> f = SettableFuture.create();
48 MockCallback callback = new MockCallback("foo");
49 Futures.addCallback(f, callback, ex);
50 f.set("foo");
51 assertEquals(1, ex.runCount);
52 }
53
54
55 public void testSameThreadExecutionException() {
56 SettableFuture<String> f = SettableFuture.create();
57 Exception e = new IllegalArgumentException("foo not found");
58 MockCallback callback = new MockCallback(e);
59 Futures.addCallback(f, callback);
60 f.setException(e);
61 }
62
63 public void testCancel() {
64 SettableFuture<String> f = SettableFuture.create();
65 FutureCallback<String> callback =
66 new FutureCallback<String>() {
67 private boolean called = false;
68 @Override
69 public void onSuccess(String result) {
70 fail("Was not expecting onSuccess() to be called.");
71 }
72
73 @Override
74 public synchronized void onFailure(Throwable t) {
75 assertFalse(called);
76 assertTrue(t instanceof CancellationException);
77 called = true;
78 }
79 };
80 Futures.addCallback(f, callback);
81 f.cancel(true);
82 }
83
84 public void testThrowErrorFromGet() {
85 Error error = new AssertionError("ASSERT!");
86 ListenableFuture<String> f = ThrowingFuture.throwingError(error);
87 MockCallback callback = new MockCallback(error);
88 Futures.addCallback(f, callback);
89 }
90
91 public void testRuntimeExeceptionFromGet() {
92 RuntimeException e = new IllegalArgumentException("foo not found");
93 ListenableFuture<String> f = ThrowingFuture.throwingRuntimeException(e);
94 MockCallback callback = new MockCallback(e);
95 Futures.addCallback(f, callback);
96 }
97
98 public void testOnSuccessThrowsRuntimeException() throws Exception {
99 RuntimeException exception = new RuntimeException();
100 String result = "result";
101 SettableFuture<String> future = SettableFuture.create();
102 @SuppressWarnings("unchecked")
103 FutureCallback<String> callback = Mockito.mock(FutureCallback.class);
104 Futures.addCallback(future, callback);
105 Mockito.doThrow(exception).when(callback).onSuccess(result);
106 future.set(result);
107 assertEquals(result, future.get());
108 Mockito.verify(callback).onSuccess(result);
109 Mockito.verifyNoMoreInteractions(callback);
110 }
111
112 public void testOnSuccessThrowsError() throws Exception {
113 class TestError extends Error {}
114 TestError error = new TestError();
115 String result = "result";
116 SettableFuture<String> future = SettableFuture.create();
117 @SuppressWarnings("unchecked")
118 FutureCallback<String> callback = Mockito.mock(FutureCallback.class);
119 Futures.addCallback(future, callback);
120 Mockito.doThrow(error).when(callback).onSuccess(result);
121 try {
122 future.set(result);
123 fail("Should have thrown");
124 } catch (TestError e) {
125 assertSame(error, e);
126 }
127 assertEquals(result, future.get());
128 Mockito.verify(callback).onSuccess(result);
129 Mockito.verifyNoMoreInteractions(callback);
130 }
131
132 public void testWildcardFuture() {
133 SettableFuture<String> settable = SettableFuture.create();
134 ListenableFuture<?> f = settable;
135 FutureCallback<Object> callback = new FutureCallback<Object>() {
136 @Override
137 public void onSuccess(Object result) {}
138
139 @Override
140 public void onFailure(Throwable t) {}
141 };
142 Futures.addCallback(f, callback);
143 }
144
145 private class CountingSameThreadExecutor implements Executor {
146 int runCount = 0;
147 @Override
148 public void execute(Runnable command) {
149 command.run();
150 runCount++;
151 }
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165 private static class ThrowingFuture<V> implements ListenableFuture<V> {
166 private final Error error;
167 private final RuntimeException runtime;
168
169 public static <V> ListenableFuture<V> throwingError(Error error) {
170 return new ThrowingFuture<V>(error);
171 }
172
173 public static <V> ListenableFuture<V>
174 throwingRuntimeException(RuntimeException e) {
175 return new ThrowingFuture<V>(e);
176 }
177
178 private ThrowingFuture(Error error) {
179 this.error = Preconditions.checkNotNull(error);
180 this.runtime = null;
181 }
182
183 public ThrowingFuture(RuntimeException e) {
184 this.runtime = Preconditions.checkNotNull(e);
185 this.error = null;
186 }
187
188 @Override
189 public boolean cancel(boolean mayInterruptIfRunning) {
190 return false;
191 }
192
193 @Override
194 public boolean isCancelled() {
195 return false;
196 }
197
198 @Override
199 public boolean isDone() {
200 return true;
201 }
202
203 @Override
204 public V get() {
205 throwOnGet();
206 throw new AssertionError("Unreachable");
207 }
208
209 @Override
210 public V get(long timeout, TimeUnit unit) {
211 throwOnGet();
212 throw new AssertionError("Unreachable");
213 }
214
215 @Override
216 public void addListener(Runnable listener, Executor executor) {
217 executor.execute(listener);
218 }
219
220 private void throwOnGet() {
221 if (error != null) {
222 throw error;
223 } else {
224 throw runtime;
225 }
226 }
227 }
228
229 private final class MockCallback implements FutureCallback<String> {
230 @Nullable private String value = null;
231 @Nullable private Throwable failure = null;
232 private boolean wasCalled = false;
233
234 MockCallback(String expectedValue) {
235 this.value = expectedValue;
236 }
237
238 public MockCallback(Throwable expectedFailure) {
239 this.failure = expectedFailure;
240 }
241
242 @Override
243 public synchronized void onSuccess(String result) {
244 assertFalse(wasCalled);
245 wasCalled = true;
246 assertEquals(value, result);
247 }
248
249 @Override
250 public synchronized void onFailure(Throwable t) {
251 assertFalse(wasCalled);
252 wasCalled = true;
253 assertEquals(failure, t);
254 }
255 }
256 }